#include "Cube.h"
#include <iostream>

Cube::Cube(float size)
{
    using namespace Nitro::Renderer;
    auto s = size / 2.0f;

    ShaderDescriptor shaderDesc;
    shaderDesc.type = ShaderType::VertexShader;
    shaderDesc.sourceType = ShaderSourceType::SourceFile;
    shaderDesc.source = "vs.glsl";
    vs = CreateShader(shaderDesc);
    if (vs.hasReport())
    {
        std::cout << vs.getReport();
    }
    shaderDesc.type = ShaderType::FragmentShader;
    shaderDesc.sourceType = ShaderSourceType::SourceFile;
    shaderDesc.source = "fs.glsl";
    fs = CreateShader(shaderDesc);
    if (fs.hasReport())
    {
        std::cout << fs.getReport();
    }

    PipelineDescriptor pipelineDesc;
    pipelineDesc.vertexShader = vs;
    pipelineDesc.fragmentShader = fs;
    pipelineDesc.drawMode = DrawMode::Triangles;
    pipeline = CreatePipeline(pipelineDesc);
    if (pipeline.hasReport())
    {
        std::cout << pipeline.getReport();
    }

    struct Vertex
    {
        float position[3], normal[3];
    } verts[] = {
        s,  s,  s,  0.f,  0.f,  1.f, //
        s,  -s, s,  0.f,  0.f,  1.f, //
        -s, -s, s,  0.f,  0.f,  1.f, //
        -s, s,  s,  0.f,  0.f,  1.f, //

        s,  s,  -s, 0.f,  0.f,  -1.f, //
        s,  -s, -s, 0.f,  0.f,  -1.f, //
        -s, -s, -s, 0.f,  0.f,  -1.f, //
        -s, s,  -s, 0.f,  0.f,  -1.f, //

        s,  s,  s,  1.f,  0.f,  0.f, //
        s,  -s, s,  1.f,  0.f,  0.f, //
        s,  s,  -s, 1.f,  0.f,  0.f, //
        s,  -s, -s, 1.f,  0.f,  0.f, //

        -s, -s, s,  -1.f, 0.f,  0.f, //
        -s, s,  s,  -1.f, 0.f,  0.f, //
        -s, -s, -s, -1.f, 0.f,  0.f, //
        -s, s,  -s, -1.f, 0.f,  0.f, //

        s,  s,  s,  0.f,  1.f,  0.f, //
        -s, s,  s,  0.f,  1.f,  0.f, //
        s,  s,  -s, 0.f,  1.f,  0.f, //
        -s, s,  -s, 0.f,  1.f,  0.f, //

        s,  -s, s,  0.f,  -1.f, 0.f, //
        -s, -s, s,  0.f,  -1.f, 0.f, //
        s,  -s, -s, 0.f,  -1.f, 0.f, //
        -s, -s, -s, 0.f,  -1.f, 0.f, //
    };

    std::vector<uint32_t> indices = {
        0,  1,  2,  0,  2,  3,  //
        4,  5,  6,  4,  6,  7,  //
        8,  9,  11, 8,  10, 11, //
        12, 13, 15, 12, 14, 15, //
        16, 17, 19, 16, 18, 19, //
        20, 21, 23, 20, 22, 23, //
    };

    BufferDescriptor bufferDesc;
    bufferDesc.bindFlags = BindFlags::VertexBuffer;
    bufferDesc.size = sizeof(verts);
    bufferDesc.appendAttribute(0, sizeof(Vertex), Format::RGB32Float);
    bufferDesc.appendAttribute(3 * sizeof(float), sizeof(Vertex),
                               Format::RGB32Float);
    vertexBuffer = CreateBuffer(bufferDesc, verts);

    bufferDesc.bindFlags = BindFlags::IndexBuffer;
    bufferDesc.size = sizeof(decltype(indices)::value_type) * indices.size();
    indexBuffer = CreateBuffer(bufferDesc, indices.data());
}

void Cube::render()
{
    using namespace glm;
    updateMatrix();
    pipeline.activate();
    pipeline.setUniform("modelMatrix", modelMatrix);
    pipeline.setUniform("normalMatrix", mat3(transpose(inverse(modelMatrix))));
    pipeline.setUniform("viewProjectionMatrix", viewProjectionMatrix);
    pipeline.setVertexBuffer(vertexBuffer);
    pipeline.setIndexBuffer(indexBuffer);
    pipeline.drawIndexed(0, 36);
}